
#ifndef __MQTTCLIENT_H__
#define __MQTTCLIENT_H__

#include "mosquittopp.h"
#include "Function.hxx"
#include "Thread.hxx"
#include <unordered_map>
#include <functional>
#include <queue>
#include <atomic>

using namespace std;

class CMqttClient : public mosqpp::mosquittopp, public CThread
{
public:
    explicit CMqttClient();
    virtual ~CMqttClient();

    bool Init(const char* host = "127.0.0.1", int port = 1883, int qos = 1);
    bool ReInit(const char* host = "127.0.0.1", int port = 1883, int qos = 1);
    bool CleanUp();
    bool CheckBrokerAlive(const char* host = "127.0.0.1", int port = 1883, int qos = 1);

    bool Start();
    bool Stop();
    bool Restart();

    int WillSet(const string& strTopic, const string& strMsg);
    int WillClear();

    int Publish(const string& strTopic, const string& strMsg, bool retain = false);

    int Subscribe(const string& strTopic);
    int Unsubscribe(const string& strTopic);

    using StateChangeCallback = function<int(void* data, unsigned short len)>;
    using RecvMessageCallback = function<int(void* data, unsigned short len)>;

    void RegisterStateCallback(const StateChangeCallback& fun);
    void UnRegisterStateCallback();

    void RegisterRecvMessageCallback(const RecvMessageCallback& fun);
    void UnRegistRecvMessageCallback();

    bool DeleteRetainMsg(const string& strTopic);
    bool EnableLog(bool bEnable);
    void PrintDebugInfo();
    int  GetMachineSize();

public:
    struct ClientState
    {
        bool bOnline;  //与broke连接：true /false
        ClientState()
            : bOnline(false)
        {
        }
        BOOL operator==(const ClientState t) const
        {
            return ((this->bOnline == t.bOnline));
        }
        ClientState& operator=(const ClientState& t)
        {
            this->bOnline = t.bOnline;
            return *this;
        }
    };

    struct RecvMessage
    {
        int    iMid;
        string strTopic;
        string strMsg;
        RecvMessage()
            : iMid(0)
            , strTopic("")
            , strMsg("")
        {
        }
        RecvMessage& operator=(const RecvMessage& t)
        {
            this->iMid     = t.iMid;
            this->strTopic = t.strTopic;
            this->strMsg   = t.strMsg;
            return *this;
        }
    };

    struct SendMessage
    {
        int    iMid;
        string strTopic;
        string strMsg;
        bool   bRetain;
        SendMessage()
            : iMid(0)
            , strTopic("")
            , strMsg("")
            , bRetain(false)
        {
        }
        bool operator==(const SendMessage t) const
        {
            return ((this->strTopic.compare(t.strTopic) == 0) && (this->strMsg.compare(t.strMsg) == 0));
        }
    };

    struct SendMid
    {
        int iPublishMid;
        int iSubMid;
        int iUnsubMid;
        SendMid()
            : iPublishMid(0)
            , iSubMid(0)
            , iUnsubMid(0)
        {
        }
    };

private:
    //状态机
    using pFunc_t               = string (CMqttClient::*)(void);  //返回：下一个待执行的状态机
    using MapStateMachineFunc_t = unordered_map<string, pFunc_t>;
    using ValueType             = MapStateMachineFunc_t::value_type;

private:
    virtual void on_connect(int rc) override;
    virtual void on_disconnect(int rc) override;
    virtual void on_publish(int mid) override;
    virtual void on_subscribe(int mid, int qos_count, const int* granted_qos) override;  //订阅回调函数
    virtual void on_message(const struct mosquitto_message* message) override;           //订阅主题接收到消息
    virtual void on_log(int level, const char* str) override;
    virtual void on_error() override;
    virtual void on_unsubscribe(int mid) override;

    virtual void ThreadProc();

    //状态机执行函数
    string _IdleState();
    string _AuthState();
    string _ConnectState();
    string _DisconnectState();
    string _ReconnectState();
    string _TransferState();
    bool   _EnterState(const string& strSta);
    string _GetNextState();

private:
    atomic<bool>                       m_bConnect;  //是否已经和broker连接
    int                                m_qos;
    CMutex                             m_Mutex;
    const static MapStateMachineFunc_t m_MapStateMachineFunc;
    string                             m_StateMachine;  //当前状态机
    string                             m_strHost;
    int                                m_iPort;
    vector<string>                     m_vecSubTopic;
    StateChangeCallback                m_StateChangeFun;
    RecvMessageCallback                m_RecvMessageFun;
    CMutex                             m_StateMachineMutex;
    vector<SendMessage>                m_VecRetainMsg;           //Retain保留消息队列缓存
    queue<string>                      m_queueNextStateMachine;  //待切换的状态机切换任务队列
    SendMid                            m_stMid;                  //发送序列表，每发送一次自动+1
    bool                               m_bStart;                 //状态机启动标志
    bool                               m_bLog;                   //是否打开mqtt库日志
    atomic<bool>                       m_bSendFlag;              //是否发送信息给MQTT
    CMutex                             m_MutexMqttSubmit;        //MQTT信息上报锁
};

#endif  //__MQTTCLIENT_H__
